#import "AliyunOss.h"
#import <React/RCTLog.h>

#import <AliyunOSSiOS/OSSService.h>

static const int SUCCESS = 100;
static const int ERROR = 101;

OSSClient* _client;

@implementation AliyunOss

RCT_EXPORT_MODULE();

- (NSDictionary *) constantsToExport{
  return @{
    @"SUCCESS": [NSNumber numberWithInt: SUCCESS],
    @"ERROR": [NSNumber numberWithInt: ERROR]
  };
}

+ (BOOL) requiresMainQueueSetup {
  return NO;
}

RCT_EXPORT_METHOD(initWithSigner:(NSString *)endPoint
                         signUrl:(NSString *)signUrl){
  id<OSSCredentialProvider> credential =
    [[OSSCustomSignerCredentialProvider alloc]
     initWithImplementedSigner:
                            ^NSString *(NSString *contentToSign,
                            NSError *__autoreleasing *error) {
       NSString *encodeContent = [contentToSign stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
       NSString *urlString = [NSString stringWithFormat: @"%@?content=%@", signUrl, encodeContent];
    
       NSURL *url = [NSURL URLWithString: urlString];
       NSURLRequest *request = [NSURLRequest requestWithURL: url];
       OSSTaskCompletionSource *tcs = [OSSTaskCompletionSource taskCompletionSource];
       NSURLSession *session = [NSURLSession sharedSession];
       // 发送请求
       NSURLSessionTask *sessionTask = [session dataTaskWithRequest: request
                                                completionHandler: ^(NSData *data,
                                                                     NSURLResponse *response,
                                                                     NSError *error) {
                                                                       if (error) {
                                                                           [tcs setError: error];
                                                                           return;
                                                                       }
                                                                       [tcs setResult: data];
                                                                     }];
       [sessionTask resume];
       // 需要阻塞等待请求返回。
       [tcs.task waitUntilFinished];
       
       if (tcs.task.error) {
           return nil;
       }else {
           NSData *resData = tcs.task.result;
           return [[NSString alloc] initWithData: resData encoding: NSUTF8StringEncoding];
       }
    }];

  _client = [[OSSClient alloc] initWithEndpoint: endPoint credentialProvider: credential];
}

RCT_EXPORT_METHOD(asyncUpload:(NSString *)bucket
                          key:(NSString *)key
                         path:(NSString *)path
                     resolver:(RCTPromiseResolveBlock)resolve
                     rejecter:(RCTPromiseRejectBlock)reject){
  OSSPutObjectRequest *put = [OSSPutObjectRequest new];
  
  put.bucketName = bucket;
  put.objectKey = key;
  put.uploadingFileURL = [NSURL fileURLWithPath: path];
  
  OSSTask *putTask = [_client putObject: put];
  
  [putTask continueWithBlock: ^id(OSSTask *task) {
    if (!task.error) {
        resolve([NSNumber numberWithInt: SUCCESS]);
    } else {
        resolve([NSNumber numberWithInt: ERROR]);
        
        RCTLogInfo(@"upload object failed, error: %@", task.error);
    }
    return nil;
  }];
}

RCT_EXPORT_METHOD(asyncUploadPublic:(NSString *)bucket
                                key:(NSString *)key
                               path:(NSString *)path
                           resolver:(RCTPromiseResolveBlock)resolve
                           rejecter:(RCTPromiseRejectBlock)reject){
  OSSPutObjectRequest *put = [OSSPutObjectRequest new];
  
  put.bucketName = bucket;
  put.objectKey = key;
  put.uploadingFileURL = [NSURL fileURLWithPath: path];
  
  put.objectMeta = [NSMutableDictionary 
    dictionaryWithObjectsAndKeys: @"public-read", @"x-oss-object-acl", nil];

  OSSTask *putTask = [_client putObject: put];
  
  [putTask continueWithBlock: ^id(OSSTask *task) {
    if (!task.error) {
        resolve([NSNumber numberWithInt: SUCCESS]);
    } else {
        resolve([NSNumber numberWithInt: ERROR]);
        
        RCTLogInfo(@"upload object failed, error: %@", task.error);
    }
    return nil;
  }];
}

@end
